home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / OS / ZHandle.cpp < prev    next >
Text File  |  1997-06-20  |  16KB  |  769 lines

  1. /*
  2.  *  File:        ZHandle.h
  3.  *  Summary:    A class to encapsulate relocatable memory.
  4.  *  Written by:    Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996-1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):    
  10.  *
  11.  *         <3>     6/20/97    JDJ        Ctors use new SHandleOptions to work around ambiguity problems.
  12.  *         <2>     5/17/97    JDJ        Added an Invariant to ZHandleRef. OnLock now adds a
  13.  *                                    tail to the handle.
  14.  *         <1>     1/14/96    JDJ        Created
  15.  */
  16.  
  17. #include <ZHandle.h>
  18.  
  19. #include <Errors.h>
  20. #include <Resources.h>
  21.  
  22. #include <ZConstants.h>
  23. #include <ZDebug.h>
  24. #include <ZExceptions.h>
  25. #include <ZMemUtils.h>
  26. #include <ZMiscUtils.h>
  27. #include <ZReferenceCounted.h>
  28. #include <ZResUtils.h>
  29. #include <ZStringUtils.h>
  30.  
  31.  
  32. //-----------------------------------
  33. //    Constants
  34. //
  35. const long kTail = 0x26374859L;
  36.  
  37.  
  38. // ===================================================================================
  39. //    class ZHandleRef
  40. // ===================================================================================
  41. class ZHandleRef : public MInvariant, public MReferenceCounted, public MLockable {
  42.  
  43.     typedef MInvariant Inherited;
  44.     friend THandle;
  45.  
  46. //-----------------------------------
  47. //    Initialization/Destruction
  48. //
  49. public:
  50.     virtual             ~ZHandleRef();
  51.  
  52.                         ZHandleRef(ulong bytes, const SHandleOptions& options);
  53.  
  54.                         ZHandleRef(Handle macHandle);
  55.  
  56. //-----------------------------------
  57. //    New API
  58. //
  59. public:
  60.     // ----- Access -----
  61.             const Byte* GetPtr() const;
  62.  
  63.             Byte*         GetPtr();
  64.  
  65.             Handle         GetHandle() const;
  66.  
  67.     // ----- Sizing -----
  68.             ulong         GetSize() const;
  69.  
  70.             OSErr         SetSize(ulong bytes, bool zeroBytes);
  71.  
  72.     // ----- Debugging -----
  73.             void         AddTail();
  74.  
  75.             void         CheckTail() const;
  76.             
  77.             void         RemoveTail();
  78.  
  79. //-----------------------------------
  80. //    Inherited API
  81. //
  82. protected:
  83.     virtual void         Invariant() const;
  84.     
  85.     virtual void         OnLock(bool moveHigh);
  86.  
  87.     virtual void         OnUnlock();
  88.  
  89. //-----------------------------------
  90. //    Member data
  91. //
  92. private:
  93.     Handle        mHandle;
  94.     bool        mHasTail;
  95. };
  96.  
  97.  
  98. //---------------------------------------------------------------
  99. //
  100. // ZHandleRef::~ZHandleRef
  101. //
  102. //---------------------------------------------------------------
  103. ZHandleRef::~ZHandleRef()
  104. {
  105.     ASSERT(!mHasTail);
  106.     
  107.     DisposeIfHandle(mHandle);
  108. }
  109.  
  110.  
  111. //---------------------------------------------------------------
  112. //
  113. // ZHandleRef::ZHandleRef (ulong, SHandleOptions)
  114. // 
  115. //---------------------------------------------------------------
  116. ZHandleRef::ZHandleRef(ulong bytes, const SHandleOptions& options) 
  117. {
  118.     ASSERT(bytes < 16*1024L*1024L);
  119.     
  120.     mHasTail = false;
  121.     
  122.     mHandle = CreateHandle(bytes, options.options);
  123.     ThrowIfMemFail(mHandle);
  124. }
  125.  
  126.  
  127. //---------------------------------------------------------------
  128. //
  129. // ZHandleRef::ZHandleRef (Handle)
  130. //
  131. //---------------------------------------------------------------
  132. ZHandleRef::ZHandleRef(Handle takeHandle)
  133. {
  134.     ValidateHandle(takeHandle);
  135.     
  136.     mHasTail = false;
  137.     mHandle = takeHandle;
  138.     
  139.     if (IsResource(mHandle)) {
  140.         if (*mHandle == nil) {
  141.             LoadResource(mHandle);
  142.             ThrowIfResError();
  143.         }
  144.  
  145.         HNoPurge(mHandle);
  146.         DetachResource(mHandle);
  147.         ThrowIfResError();
  148.     }
  149.     
  150.     if (::IsLocked(mHandle))
  151.         mLockCount = 1;
  152. }
  153.  
  154.  
  155. //---------------------------------------------------------------
  156. //
  157. // ZHandleRef::OnLock
  158. //
  159. //---------------------------------------------------------------
  160. void ZHandleRef::OnLock(bool moveHigh)
  161. {
  162. #if    DEBUG
  163.     this->AddTail();
  164. #endif
  165.  
  166.     if (moveHigh)
  167.         MoveHHi(mHandle);
  168.         
  169.     HLock(mHandle);
  170. }
  171.  
  172.  
  173. //---------------------------------------------------------------
  174. //
  175. // ZHandleRef::OnUnlock
  176. //
  177. //---------------------------------------------------------------
  178. void ZHandleRef::OnUnlock()
  179. {
  180.     HUnlock(mHandle);
  181.  
  182. #if    DEBUG
  183.     this->RemoveTail();            
  184. #endif
  185. }
  186.  
  187.  
  188. //---------------------------------------------------------------
  189. //
  190. // ZHandleRef::GetPtr
  191. //
  192. //---------------------------------------------------------------
  193. inline const Byte* ZHandleRef::GetPtr() const
  194. {
  195.     return (Byte *) StripAddress(*mHandle);
  196. }
  197.  
  198.  
  199. //---------------------------------------------------------------
  200. //
  201. // ZHandleRef::GetPtr
  202. //
  203. //---------------------------------------------------------------
  204. inline Byte* ZHandleRef::GetPtr()
  205. {
  206.     return (Byte *) StripAddress(*mHandle);
  207. }
  208.  
  209.  
  210. //---------------------------------------------------------------
  211. //
  212. // ZHandleRef::GetHandle
  213. //
  214. //---------------------------------------------------------------
  215. inline Handle ZHandleRef::GetHandle() const
  216. {
  217.     ValidateHandle(mHandle);
  218.     
  219.     return mHandle;
  220. }
  221.  
  222.  
  223. //---------------------------------------------------------------
  224. //
  225. // ZHandleRef::GetSize
  226. //
  227. //---------------------------------------------------------------
  228. inline ulong ZHandleRef::GetSize() const
  229. {
  230.     long size = ::GetHandleSize(mHandle);
  231.     if (mHasTail)
  232.         size -= 4;
  233.  
  234.     return (ulong) size;
  235. }
  236.  
  237.  
  238. //---------------------------------------------------------------
  239. //
  240. // ZHandleRef::SetSize
  241. //
  242. //---------------------------------------------------------------
  243. OSErr ZHandleRef::SetSize(ulong bytes, bool zeroBytes)
  244. {
  245.     PRECONDITION(!mHasTail);
  246.     ASSERT(bytes < 16*1024L*1024L);
  247.     
  248.     OSErr err = noErr;
  249.  
  250.     long oldSize = ::GetHandleSize(mHandle);
  251.  
  252.     if (bytes != oldSize) {
  253.         ::SetHandleSize(mHandle, bytes);
  254.         err = MemError();
  255.  
  256.         if (err == noErr && zeroBytes && bytes > oldSize)
  257.             ClearMemory(*mHandle + oldSize, bytes - oldSize);
  258.     }
  259.  
  260.     POSTCONDITION(!mHasTail);
  261.  
  262.     return err;
  263. }
  264.  
  265.  
  266. //---------------------------------------------------------------
  267. //
  268. // ZHandleRef::AddTail
  269. //
  270. //---------------------------------------------------------------
  271. void ZHandleRef::AddTail()
  272. {
  273. #if    DEBUG
  274.     ASSERT(!mHasTail);
  275.  
  276.     ulong len = this->GetSize();
  277.     long* p = nil;                                    // to insert another breakpoint
  278.     ThrowIfOSErr(this->SetSize(len+sizeof(long), kDontZeroBytes));
  279.  
  280.     p = (long *) (this->GetPtr() + len);
  281.     *p = kTail;
  282.  
  283.     mHasTail = true;
  284. #endif
  285. }
  286.  
  287.  
  288. //---------------------------------------------------------------
  289. //
  290. // ZHandleRef::CheckTail
  291. //
  292. //---------------------------------------------------------------
  293. void ZHandleRef::CheckTail() const
  294. {
  295. #if    DEBUG
  296.     ASSERT(mHasTail);
  297.  
  298.     ulong len = this->GetSize();                        // Note that GetSize adjusts for the tail!
  299.     long* p = (long *) (this->GetPtr() + len);
  300.     if (*p != kTail)
  301.         DEBUGSTR("The handle's tail has been changed to %lX.¥n", *p);
  302. #endif
  303. }
  304.  
  305.  
  306. //---------------------------------------------------------------
  307. //
  308. // ZHandleRef::RemoveTail
  309. //
  310. //---------------------------------------------------------------
  311. void ZHandleRef::RemoveTail()
  312. {
  313. #if    DEBUG
  314.     this->CheckTail();
  315.  
  316.     mHasTail = false;
  317.     ulong len = this->GetSize();                        // Note that GetSize adjusts for the tail!
  318.     ThrowIfOSErr(this->SetSize(len, kDontZeroBytes));
  319. #endif
  320. }
  321.  
  322.  
  323. //---------------------------------------------------------------
  324. //
  325. // ZHandleRef::Invariant
  326. //
  327. //---------------------------------------------------------------
  328. void ZHandleRef::Invariant() const
  329. {
  330.     Inherited::Invariant();
  331.     
  332.     ASSERT(mHandle != nil);
  333.     ASSERT(*mHandle != nil);
  334.     
  335.     if (::IsLocked(mHandle))
  336.         ASSERT(this->IsLocked());
  337.  
  338.     if (this->IsLocked())
  339.         ASSERT(::IsLocked(mHandle));
  340.  
  341.     if (mHasTail)
  342.         this->CheckTail();
  343. }
  344.  
  345. #pragma mark -
  346.  
  347. // ===================================================================================
  348. //    class THandle
  349. // ===================================================================================
  350.  
  351. //---------------------------------------------------------------
  352. //
  353. // THandle::~THandle
  354. //
  355. //---------------------------------------------------------------
  356. THandle::~THandle()
  357. {
  358.     mHandleRef->RemoveReference();
  359. }
  360.  
  361.  
  362. //---------------------------------------------------------------
  363. //
  364. // THandle::THandle (ulong, SHandleOptions)
  365. //
  366. //---------------------------------------------------------------
  367. THandle::THandle(ulong bytes, const SHandleOptions& options)
  368. {
  369.     mHandleRef = new ZHandleRef(bytes, options);
  370. }
  371.  
  372.  
  373. //---------------------------------------------------------------
  374. //
  375. // THandle::THandle (Handle)
  376. //
  377. //---------------------------------------------------------------
  378. THandle::THandle(Handle takeHandle)
  379. {
  380.     ASSERT(takeHandle != nil);
  381.  
  382.     try {
  383.         mHandleRef = new ZHandleRef(takeHandle);
  384.         
  385.     } catch (...) {
  386.         if (IsResource(takeHandle))
  387.             ReleaseResource(takeHandle);
  388.         else
  389.             DisposeHandle(takeHandle);
  390.             
  391.         throw;
  392.     }
  393. }
  394.  
  395.  
  396. //---------------------------------------------------------------
  397. //
  398. // THandle::THandle (THandle)
  399. //
  400. //---------------------------------------------------------------
  401. THandle::THandle(const THandle& hand)
  402. {
  403.     mHandleRef = hand.mHandleRef;
  404.     mHandleRef->AddReference();
  405. }
  406.  
  407.  
  408. //---------------------------------------------------------------
  409. //
  410. // THandle::THandle (ResType, ResID, SHandleOptions, short)
  411. //
  412. //---------------------------------------------------------------
  413. THandle::THandle(ResType type, ResID id, const SHandleOptions& options, short fileRef)
  414. {
  415.     Handle rsrc = nil;
  416.     
  417.     try {
  418.         TSaveResFile setFile(fileRef);
  419.         
  420.             // Read the resource into the app's heap, but don't read the resource's data.
  421.             SetResLoad(false);
  422.             if (fileRef == kNoFileRefNum)
  423.                 rsrc = GetResource(type, id);
  424.             else
  425.                 rsrc = Get1Resource(type, id);
  426.             OSErr err = ResError();
  427.             SetResLoad(true);
  428.             if (rsrc == nil && err == noErr)
  429.                 err = resNotFound;
  430.             ThrowIfOSErr(err);
  431.             
  432.             // Find the size of the resource's data.
  433.             ulong bytes = (ulong) GetResourceSizeOnDisk(rsrc);
  434.             ThrowIfResError();
  435.  
  436.             // Allocate a handle of the right size in the correct location.
  437.             mHandleRef = new ZHandleRef(bytes, options);
  438.  
  439.             // Read in the resource's data.
  440.             this->Lock();
  441.             ReadPartialResource(rsrc, 0, this->GetPtr(), (long) bytes);
  442.             err = ResError();
  443.             this->Unlock();
  444.             ThrowIfOSErr(err);
  445.  
  446.             // Release our resource handle.
  447.             ReleaseResource(rsrc);            
  448.             rsrc = nil;
  449.         
  450.     } catch (...) {
  451.         ReleaseIfResource(rsrc);
  452.         throw;
  453.     }
  454. }
  455.  
  456.  
  457. //---------------------------------------------------------------
  458. //
  459. // THandle::THandle (ResType, string, SHandleOptions, short)
  460. //
  461. //---------------------------------------------------------------
  462. THandle::THandle(ResType type, const string& name, const SHandleOptions& options, short fileRef)
  463. {
  464.     Handle rsrc = nil;
  465.     
  466.     try {
  467.         TSaveResFile setFile(fileRef);
  468.         
  469.             // Read the resource into the app's heap, but don't read the resource's data.
  470.             SetResLoad(false);
  471.             if (fileRef == kNoFileRefNum)
  472.                 rsrc = GetNamedResource(type, StrToPStr(name));
  473.             else
  474.                 rsrc = Get1NamedResource(type, StrToPStr(name));
  475.             OSErr err = ResError();
  476.             SetResLoad(true);
  477.             if (rsrc == nil && err == noErr)
  478.                 err = resNotFound;
  479.             ThrowIfOSErr(err);
  480.             
  481.             // Find the size of the resource's data.
  482.             ulong bytes = (ulong) GetResourceSizeOnDisk(rsrc);
  483.             ThrowIfResError();
  484.  
  485.             // Allocate a handle of the right size in the correct location.
  486.             mHandleRef = new ZHandleRef(bytes, options);
  487.  
  488.             // Read in the resource's data.
  489.             this->Lock();
  490.             ReadPartialResource(rsrc, 0, this->GetPtr(), (long) (bytes));
  491.             err = ResError();
  492.             this->Unlock();
  493.             ThrowIfOSErr(err);
  494.  
  495.             // Release our resource handle.
  496.             ReleaseResource(rsrc);
  497.             rsrc = nil;
  498.         
  499.     } catch (...) {
  500.         ReleaseIfResource(rsrc);
  501.         throw;
  502.     }
  503. }
  504.  
  505.  
  506. //---------------------------------------------------------------
  507. //
  508. // THandle::operator=
  509. //
  510. //---------------------------------------------------------------
  511. THandle& THandle::operator=(const THandle& hand)
  512. {
  513.     ASSERT(!this->IsLocked());
  514.     
  515.     if (mHandleRef != hand.mHandleRef) {
  516.         mHandleRef->RemoveReference();
  517.  
  518.         hand.mHandleRef->AddReference();
  519.         mHandleRef = hand.mHandleRef;
  520.     }
  521.     
  522.     return *this;
  523. }
  524.  
  525.  
  526. //---------------------------------------------------------------
  527. //
  528. // THandle::Detach
  529. //
  530. //---------------------------------------------------------------
  531. void THandle::Detach()
  532. {
  533.     ASSERT(!this->IsLocked());
  534.     
  535.     if (mHandleRef->GetRefCount() > 1) {
  536.         Handle data = mHandleRef->GetHandle();
  537.         
  538.         OSErr err = HandToHand(&data);
  539.         ThrowIfOSErr(err);
  540.     
  541.         try {
  542.             ZHandleRef* newRef = new ZHandleRef(data);
  543.     
  544.             mHandleRef->RemoveReference();
  545.             mHandleRef = newRef;
  546.             
  547.         } catch(...) {
  548.             if (data != nil)
  549.                 DisposeHandle(data);
  550.             throw;
  551.         }
  552.     }
  553. }
  554.  
  555.  
  556. //---------------------------------------------------------------
  557. //
  558. // THandle::Lock
  559. //
  560. //---------------------------------------------------------------
  561. void THandle::Lock(bool moveHigh)
  562. {
  563.     mHandleRef->Lock(moveHigh);
  564. }
  565.  
  566.  
  567. //---------------------------------------------------------------
  568. //
  569. // THandle::Unlock
  570. //
  571. //---------------------------------------------------------------
  572. void THandle::Unlock()
  573. {
  574.     mHandleRef->Unlock();
  575. }
  576.  
  577.  
  578. //---------------------------------------------------------------
  579. //
  580. // THandle::IsLocked
  581. //
  582. //---------------------------------------------------------------
  583. bool THandle::IsLocked() const
  584. {
  585.     return mHandleRef->IsLocked();
  586. }
  587.     
  588.  
  589. //---------------------------------------------------------------
  590. //
  591. // THandle::GetPtr
  592. //
  593. //---------------------------------------------------------------
  594. const Byte* THandle::GetPtr() const
  595. {
  596.     ASSERT(mHandleRef->IsLocked());
  597.     
  598.     const Byte* ptr = mHandleRef->GetPtr();
  599.  
  600.     return ptr;
  601. }
  602.  
  603.  
  604. //---------------------------------------------------------------
  605. //
  606. // THandle::GetPtr
  607. //
  608. //---------------------------------------------------------------
  609. Byte* THandle::GetPtr()
  610. {
  611.     ASSERT(mHandleRef->IsLocked());
  612.  
  613.     Byte* ptr = mHandleRef->GetPtr();
  614.  
  615.     return ptr;
  616. }
  617.  
  618.  
  619. //---------------------------------------------------------------
  620. //
  621. // THandle::GetUnsafePtr
  622. //
  623. //---------------------------------------------------------------
  624. const Byte* THandle::GetUnsafePtr() const
  625. {
  626.     const Byte* ptr = mHandleRef->GetPtr();
  627.  
  628.     return ptr;
  629. }
  630.  
  631.  
  632. //---------------------------------------------------------------
  633. //
  634. // THandle::GetUnsafePtr
  635. //
  636. //---------------------------------------------------------------
  637. Byte* THandle::GetUnsafePtr()
  638. {
  639.     Byte* ptr = mHandleRef->GetPtr();
  640.  
  641.     return ptr;
  642. }
  643.  
  644.  
  645. //---------------------------------------------------------------
  646. //
  647. // THandle::operator Handle
  648. //
  649. //---------------------------------------------------------------
  650. THandle::operator Handle() const
  651. {
  652.     Handle hand = mHandleRef->GetHandle();
  653.  
  654.     return hand;
  655. }
  656.  
  657.  
  658. //---------------------------------------------------------------
  659. //
  660. // THandle::AddTail
  661. //
  662. //---------------------------------------------------------------
  663. void THandle::AddTail()
  664. {
  665. #if DEBUG
  666.     mHandleRef->AddTail();
  667. #endif
  668. }
  669.  
  670.  
  671. //---------------------------------------------------------------
  672. //
  673. // THandle::CheckTail
  674. //
  675. //---------------------------------------------------------------
  676. void THandle::CheckTail() const
  677. {
  678. #if DEBUG
  679.     mHandleRef->CheckTail();
  680. #endif
  681. }
  682.  
  683.  
  684. //---------------------------------------------------------------
  685. //
  686. // THandle::RemoveTail
  687. //
  688. //---------------------------------------------------------------
  689. #pragma segment ZDebug
  690. void THandle::RemoveTail()
  691. {
  692. #if DEBUG
  693.     mHandleRef->RemoveTail();
  694. #endif
  695. }
  696.  
  697.  
  698. //---------------------------------------------------------------
  699. //
  700. // THandle::GetSize
  701. //
  702. //---------------------------------------------------------------
  703. ulong THandle::GetSize() const
  704. {
  705.     ulong size = mHandleRef->GetSize();
  706.      
  707.     return size;
  708. }
  709.  
  710.  
  711. //---------------------------------------------------------------
  712. //
  713. // THandle::SetSize
  714. //
  715. //---------------------------------------------------------------
  716. void THandle::SetSize(ulong bytes, bool zeroBytes)
  717. {
  718.     ASSERT(!this->IsLocked() || bytes < this->GetSize());    // it's really bad practice to try and expand a locked handle.
  719.  
  720.     ThrowIfOSErr(mHandleRef->SetSize(bytes, zeroBytes));
  721. }
  722.  
  723.  
  724. //---------------------------------------------------------------
  725. //
  726. // THandle::CanPurge
  727. //
  728. //---------------------------------------------------------------
  729. bool THandle::CanPurge(Handle gzHandle) const
  730. {
  731.     return mHandleRef->GetHandle() != gzHandle && !this->IsLocked();
  732. }
  733.  
  734.  
  735. //---------------------------------------------------------------
  736. //
  737. // THandle::CanPurge
  738. //
  739. // Outlined so we can be sure it's in a resident segment.
  740. //
  741. //---------------------------------------------------------------
  742. ulong THandle::PurgeableBytes() const
  743. {
  744.     return this->GetSize();
  745. }
  746.  
  747.  
  748. //---------------------------------------------------------------
  749. //
  750. // THandle::operator==
  751. //
  752. //---------------------------------------------------------------
  753. bool THandle::operator==(const THandle& rhs) const
  754. {
  755.     bool equal = mHandleRef == rhs.mHandleRef;
  756.     
  757.     if (!equal) {
  758.         ulong crc1 = ComputeCRC(this->GetUnsafePtr(), this->GetSize());
  759.         ulong crc2 = ComputeCRC(rhs.GetUnsafePtr(), rhs.GetSize());
  760.         
  761.         equal = crc1 == crc2;
  762.     }
  763.     
  764.     return equal;
  765. }
  766.  
  767.  
  768.  
  769.